home *** CD-ROM | disk | FTP | other *** search
/ Apple WWDC 1996 / WWDC96_1996 (CD).toast / Technology Materials / MacApp Release 10 / MacApp Release 10 - HD Ready / Libraries / Core / Sources / UniversalStartup.cp < prev    next >
Encoding:
Text File  |  1996-04-03  |  13.9 KB  |  451 lines  |  [TEXT/MPS ]

  1. //----------------------------------------------------------------------------------------
  2. // UniversalStartup.cp 
  3. // Copyright © 1984-96 by Apple Computer, Inc. All rights reserved.
  4. //----------------------------------------------------------------------------------------
  5.  
  6.  
  7. #ifndef __UNIVERSALSTARTUP__
  8. #include "UniversalStartup.h"
  9. #endif
  10.  
  11. // MacApp
  12.  
  13. #ifndef __UCOREERRORMGR__
  14. #include "UCoreErrorMgr.h"
  15. #endif
  16.  
  17. #ifndef __UCOREUTILITIES__
  18. #include "UCoreUtilities.h"
  19. #endif
  20.  
  21. // Toolbox
  22.  
  23. #ifndef __DIALOGS__
  24. #include <Dialogs.h>
  25. #endif
  26.  
  27. #ifndef __GESTALT__
  28. #include <Gestalt.h>
  29. #endif
  30.  
  31. #ifndef __RESOURCES__
  32. #include <Resources.h>
  33. #endif
  34.  
  35. #ifndef __FONTS__
  36. #include <Fonts.h>
  37. #endif
  38.  
  39. #ifndef __TOOLUTILS__
  40. #include <ToolUtils.h>
  41. #endif
  42.  
  43. #ifndef __LOWMEM__
  44. #include <LowMem.h>
  45. #endif
  46.  
  47. //••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
  48. // B E G I N   U N I V E R S A L   C O D E
  49. //
  50. // The following is universal code. That is, code that must be compiled to run on any
  51. // processor. This is because this is the code that is called during startup, but after
  52. // we've checked for PPC so this can be PPC code. This code will properly initialize the
  53. // toolbox, thus an alert can be shown if necessary. It must not make any calls into code
  54. // that is not "universal" code. 
  55. //
  56. //••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
  57.  
  58. #pragma push
  59. #if !qPowerPC
  60. #pragma processor 68000
  61. #endif
  62.  
  63. Boolean gHasProcessMgr;                // saved from InitToolBox for configuration info
  64. Boolean gIsOnlyBackground;            // saved from InitToolBox for configuration info
  65. Boolean gIsHighLevelEventAware;        // saved from InitToolBox for configuration info
  66. short gProcessor;                    // saved from ValidateHardware for configuration info
  67. Boolean gHasFPU;                    // saved from ValidateHardware for configuration info
  68.  
  69. Size gSizeObjectHeap;
  70. Size gSizeHeapIncrement;
  71. Size gSizeTempReserve;
  72. Size gSizeLowSpaceReserve;
  73. Size gStackTot;
  74. //========================================================================================
  75. // GLOBAL Functions
  76. //========================================================================================
  77.  
  78. //----------------------------------------------------------------------------------------
  79. // ClearTheFPU: Essential one-time initialization
  80. //
  81. //    INLINE 0x42A7,                                        // CLR.L -(A7) 
  82. //           0x42A7,                                        // CLR.L -(A7) 
  83. //           0xF21F, 0x9800;                                // FMOVEM (A7)+, FPCR/FPSR 
  84. //----------------------------------------------------------------------------------------
  85. #if !qPowerPC
  86. static void ClearTheFPU() = {0x42A7, 0x42A7, 0xF21F, 0x9800};
  87. #endif
  88.  
  89. static void InitToolBox();
  90. static void LockSegment(ConstStr255Param name, Ptr optionalUnload = NULL);
  91. static void FailedInitToolBox();
  92. static void DoRealInitToolBox();
  93. static void ExpandHeap();
  94. static void SetStackSpace(long numBytes);
  95.  
  96. extern pascal void _DataInit();                    // Routine in the A5 globals initializer 
  97. void FunctionInMAMain();                    // address of any old routine in the MAMain segment 
  98.  
  99.  
  100. //----------------------------------------------------------------------------------------
  101. // FunctionInMAMain
  102. //----------------------------------------------------------------------------------------
  103. #pragma segment MAMain
  104. // Must be in the MAMain segment
  105. void FunctionInMAMain()
  106. {
  107. }
  108.  
  109. //----------------------------------------------------------------------------------------
  110. // UniversalStartup
  111. //----------------------------------------------------------------------------------------
  112. #pragma segment Main
  113. // Must be in the Main segment since all other segments get unloaded from here.
  114.  
  115. void UniversalStartup()
  116. {
  117.     Boolean validProcessor = ValidateProcessor();
  118.  
  119. #if !qPowerPC
  120.     // the main procedure is always compiled with universal code so, the FPU must be
  121.     // reset before it is used. We could get spurious crashes or worse. Remember:
  122.     // 2+2=4 every time!
  123.     if (gHasFPU)
  124.         ClearTheFPU();
  125. #endif
  126.  
  127.     InitToolBox();
  128.  
  129.     if (!validProcessor)
  130.     {
  131.         AlertUnsupportedConfiguration();
  132.     }        
  133.     
  134.     ExpandHeap();
  135. } // UniversalStartup 
  136.  
  137. //----------------------------------------------------------------------------------------
  138. // ValidateProcessor: 
  139. //----------------------------------------------------------------------------------------
  140. #pragma segment MAMiniInit
  141.  
  142. Boolean ValidateProcessor()
  143. {
  144.     long response;
  145.     OSErr err = Gestalt(gestaltProcessorType, &response);
  146.     gProcessor = (short)response;
  147.     
  148.     err = Gestalt(gestaltFPUType, &response);
  149.     gHasFPU = response != gestaltNoFPU;
  150.  
  151.     Boolean isSupported = true;
  152.  
  153.     // Run the gauntlet of hardware support tests using the conditionally set constants. If any
  154.     // single test fails then the app is considered unsupported on this machine.
  155.  
  156.     if (qNeedsMC68020)
  157.         isSupported &= ((gProcessor != gestalt68000) &&
  158.                         (gProcessor != gestalt68010));
  159.  
  160.     if (qNeedsMC68030)
  161.         isSupported &= ((gProcessor != gestalt68000) &&
  162.                         (gProcessor != gestalt68010) &&
  163.                         (gProcessor != gestalt68020));
  164.  
  165.     if (qNeedsMC68040)
  166.         isSupported &= ((gProcessor != gestalt68000) &&
  167.                         (gProcessor != gestalt68010) &&
  168.                         (gProcessor != gestalt68020) &&
  169.                         (gProcessor != gestalt68030));
  170.     
  171.     if (qNeedsFPU)
  172.         isSupported &= gHasFPU;
  173.  
  174.     return isSupported;
  175. } // ValidateProcessor 
  176.  
  177. //----------------------------------------------------------------------------------------
  178. // UnsupportedConfiguration: 
  179. //----------------------------------------------------------------------------------------
  180. #pragma segment MAMiniInit
  181.  
  182. void AlertUnsupportedConfiguration()
  183. {
  184.     SetCursor(&qd.arrow);
  185.     
  186.     // This alert is set to preload
  187.     Alert(phUnsupportedConfiguration, NULL);
  188.     ExitToShell();                            // leave the application pronto! 
  189. } // AlertUnsupportedConfiguration
  190.  
  191. //----------------------------------------------------------------------------------------
  192. // FailedInitToolBox: This procedure is intended to be in "Main" which is already loaded
  193. //----------------------------------------------------------------------------------------
  194. #pragma segment Main
  195.  
  196. void FailedInitToolBox()
  197. {
  198. #if qDebug
  199.     DebugStr((StringPtr)"\pNot enough room to initialize ToolBox managers");
  200. #endif
  201.     ExitToShell();
  202. } // FailedInitToolBox 
  203.  
  204. //----------------------------------------------------------------------------------------
  205. // LockSegment: 
  206. //----------------------------------------------------------------------------------------
  207. #pragma segment Main
  208.  
  209. void LockSegment(ConstStr255Param name, Ptr optionalUnload)
  210. {
  211.     SetResLoad(FALSE);
  212.     Handle h = GetNamedResource('CODE', name);
  213.     OSErr theErr = ResError();
  214.     SetResLoad(TRUE);
  215.     if (h != NULL)
  216.     {
  217.         short attrs = GetResAttrs(h);
  218.         if ((attrs & resLocked) != resLocked)
  219.         {
  220.             short itsSize = GetMaxResourceSize(h);
  221.             if (*h != NULL && optionalUnload)
  222.             {
  223.                 UnloadSeg(optionalUnload);
  224.                 EmptyHandle(h);
  225.             }
  226.             short resFile = HomeResFile(h);
  227.             short fileAttrs = GetResFileAttrs(resFile);
  228.  
  229.             SetResFileAttrs(resFile, mapReadOnly); // keep the changed bit from coming on and causing an update to disk later
  230.             SetResAttrs(h, (attrs | resLocked));
  231.             SetResFileAttrs(resFile, fileAttrs);
  232.             
  233.             if (*h == NULL)
  234.             {
  235.                 ReserveMem(itsSize);
  236.                 LoadResource(h);        // now try to haul the segment in low
  237.             }
  238.             if (*h != NULL)
  239.             {
  240.                 HNoPurge(h);
  241.                 HLock(h);
  242.             }
  243.         }
  244.     }
  245.     else if (theErr != resNotFound) // it's OK if the segment doesn't exist
  246.         FailedInitToolBox();
  247. }
  248.  
  249. //----------------------------------------------------------------------------------------
  250. // DoRealInitToolBox: 
  251. //----------------------------------------------------------------------------------------
  252. #pragma segment MAMiniInit
  253.  
  254. void DoRealInitToolBox()
  255. {
  256.     // Check for process mgr then check for background only mode
  257.     long response;
  258.     if ((Gestalt(gestaltOSAttr, &response) == noErr) && (((response >> gestaltLaunchControl) & 1) != 0))
  259.     {
  260.         gHasProcessMgr = true;                // save it for later
  261.         ProcessSerialNumber psn;
  262.         psn.highLongOfPSN = 0;
  263.         psn.lowLongOfPSN = kCurrentProcess;
  264.         
  265.         ProcessInfoRec info;
  266.         info.processInfoLength = sizeof(ProcessInfoRec);
  267.         info.processName = NULL;
  268.         info.processAppSpec = NULL;
  269.  
  270.         if (GetProcessInformation(&psn, &info) == noErr)
  271.         {
  272.             gIsOnlyBackground = (info.processMode & modeOnlyBackground) ? true : false;
  273.             gIsHighLevelEventAware = (info.processMode & modeHighLevelEventAware) ? true : false;
  274.         }
  275.     }
  276.  
  277.     // Are we background only? If so, bail out...this isn't yet supported by the code.
  278.     if (!gIsOnlyBackground)
  279.     {
  280.         // init the toolbox managers
  281.         InitGraf(&qd.thePort);
  282.         InitFonts();
  283.         InitWindows();                            // creates non-relocatable for the WM port 
  284.     
  285.         // _DON'T_ flush disk-inserted or os events or you'll be sorry! 
  286.         FlushEvents(everyEvent - diskMask - osMask, 0);
  287.     
  288.         InitMenus();
  289.         TEInit();
  290.         InitDialogs(NULL);
  291.     
  292.         InitCursor();
  293.         
  294.         gToolBoxInitialized = TRUE;
  295.         
  296.         // The refnum where the application's resources should be found 
  297.         gApplicationRefNum = LMGetCurMap();  // Don't use MACurResFile, it's not universal
  298.         gCodeRefNum = LMGetCurApRefNum();    // Not necessarily the same as gApplicationRefNum under some IDE's
  299.         
  300.         // -1 == 0xFFFFFFFF, the largest 32 bit address. Our routine StripLong uses a
  301.         // pre-stripped address gStrippedAddress to avoid the yucky MPW glue. 
  302.         gStrippedAddress = StripAddress((Ptr) - 1);
  303.     }
  304.     else
  305.     {
  306. #if qDebug
  307.         DebugStr((StringPtr)"\pBackground-only apps not currently supported");
  308. #endif
  309.         ExitToShell();
  310.     }
  311. } // DoRealInitToolBox 
  312.  
  313. //----------------------------------------------------------------------------------------
  314. // InitToolBox: 
  315. //----------------------------------------------------------------------------------------
  316. #pragma segment Main
  317.  
  318. void InitToolBox()
  319. {
  320.     const short kBreathingRoom = 1024;            // Amount of heap space needed for init 
  321.  
  322. #if qSegments
  323.     // the heap and stack don't overlap. So there's enough room to init the managers. Make
  324.     // sure that the MAMiniInit Segment can be loaded and that there's still a little Room
  325.     // after that. */
  326.  
  327. #if !qModelCFM && !defined(__MWERKS__)
  328.     UnloadSeg(&_DataInit);                        // Toss some ballast
  329. #endif
  330.  
  331.     // "MAMain" this is MacApp's own code that must be resident even before/ during the
  332.     // UMemory startup. GetNamedResource will call RsrvMem which locates the handle as low
  333.     // in memory as possible. We will then lock it there just like "Main". In order for
  334.     // this to work correctly the build system will have to have set the locked bit on the
  335.     // MAMain resource.
  336.  
  337.     // These are the only 2 resources that MABuild would set to locked. 
  338.     // The following is necessary because some development environments don't automatically
  339.     // set these this resource to locked (which means they will get loaded hi in memory).
  340.     // We'll just dynamically fix that right here! (if necessary)
  341.     LockSegment("\pMain");
  342.     LockSegment("\pMAMain", (Ptr)FunctionInMAMain);
  343.  
  344.     Handle seg = GetNamedResource('CODE', "\pMAMiniInit");
  345.     if (seg)
  346.         HNoPurge(seg);    // don't let it get squished out of the heap when the grow zone
  347.                         // might get called below. However, since it is not locked it will
  348.                         // float up to the top of the heap when it is entered at
  349.                         // DoRealInitToolBox.
  350.                     
  351. #endif // qSegments
  352.     
  353.     // Attempt to ensure that there is going to be kBreathingRoom bytes available in the
  354.     // heap so that when the actual toolbox managers are initialized there is a
  355.     // significantly reduced chance that they will express their displeasure with us
  356.     // through SysErr -25 or -2. If the space is not currently available in the zone as
  357.     // shown by PurgeSpace then attempting to allocate it will let growzoneproc operate
  358.     // and grow the zone a little, as necessary. If, after that, we haven't been able to
  359.     // get the breathing room we desire then just give up and fade silently away. (Like
  360.     // the old soldier, not the old executive).
  361.  
  362.     Size totalSize = 0;
  363.     Size contigSize = 0;
  364.     PurgeSpace(&totalSize, &contigSize);
  365.  
  366.     if (totalSize >= kBreathingRoom)
  367.         DoRealInitToolBox();
  368.     else
  369.     {
  370.         Handle breathingRoom = NewHandle(kBreathingRoom);
  371.         if (breathingRoom != NULL)                            // get the grow space 
  372.         {
  373.             DisposeHandle(breathingRoom);
  374.             DoRealInitToolBox();
  375.         }
  376.         else
  377.              FailedInitToolBox();                // Give up 
  378.     }
  379. } // InitToolBox 
  380.  
  381. //----------------------------------------------------------------------------------------
  382. // ExpandHeap: 
  383. //----------------------------------------------------------------------------------------
  384. #pragma segment Main
  385.  
  386. void ExpandHeap()
  387. {
  388.     // Sum up the standard memory requirements
  389.     // and add on the processor dependent memory requirements
  390.     // Then expand the heap while preserving the requested stack space
  391.     
  392.     const ResType memResType[2] = { 'mem!'
  393. #if qPowerPC
  394.     , 'ppc!'
  395. #else
  396.     , '68k!'
  397. #endif
  398.     };
  399.     
  400.     for (int whichType = 0; whichType < 2; whichType++)
  401.     {
  402.         ResType whichResType = memResType[whichType];
  403.         ResNumber rsrcCnt = CountResources(whichResType);
  404.         for (ResNumber i = 1; i <= rsrcCnt; ++i)
  405.         {
  406.             Handle h = GetIndResource(whichResType, i);
  407.             {
  408.                 const Mem &memH = **((MemHandle)h);
  409.     
  410.                 gSizeObjectHeap += memH.objectHeap;
  411.                 gSizeHeapIncrement += memH.heapIncrement;
  412.                 gSizeTempReserve += memH.codeVal;
  413.                 gSizeLowSpaceReserve += memH.lowSpaceVal;
  414.                 gStackTot += memH.stackVal;
  415.             }
  416.             ReleaseResource(h);
  417.         }
  418.     }
  419.     
  420.     SetStackSpace(gStackTot);
  421.  
  422.     MaxApplZone();
  423. } // ExpandHeap 
  424.  
  425. //----------------------------------------------------------------------------------------
  426. // SetStackSpace: 
  427. //----------------------------------------------------------------------------------------
  428. #pragma segment MAMiniInit
  429.  
  430. void SetStackSpace(long numBytes)
  431. {
  432.     // Make sure numBytes is even (don't use the "odd" macro in case it outlines
  433.     if (numBytes & 0x00000001)
  434.         numBytes++;
  435.  
  436.     long newLimit = (long)LMGetCurStackBase() - numBytes;
  437.     if ((long)GetApplLimit() > newLimit)
  438.         SetApplLimit((Ptr)newLimit);
  439. } // SetStackSpace 
  440.  
  441. #pragma pop
  442.  
  443. //••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
  444. // E N D   U N I V E R S A L   C O D E
  445. //••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
  446.  
  447. //----------------------------------------------------------------------------------------
  448. // End of UniversalStartup.cp
  449.  
  450. #pragma segment Inline
  451.